home *** CD-ROM | disk | FTP | other *** search
/ MacWorld UK 2000 March / MW_UK_2000_03.iso / Shareware World / Utilities / Text Processing / Alpha / Tcl / SystemCode / search.tcl < prev    next >
Encoding:
Text File  |  1999-10-24  |  19.8 KB  |  681 lines  |  [TEXT/ALFA]

  1. ## -*-Tcl-*-
  2.  # ###################################################################
  3.  #  Alpha - new Tcl folder configuration
  4.  # 
  5.  #  FILE: "search.tcl"
  6.  #                                    created: 13/6/95 {8:56:37 pm} 
  7.  #                                last update: 24/10/1999 {3:26:18 pm} 
  8.  #  
  9.  # Reorganisation carried out by Vince Darley with much help from Tom 
  10.  # Fetherston, Johan Linde and suggestions from the Alpha-D mailing list.  
  11.  # Alpha is shareware; please register with the author using the register 
  12.  # button in the about box.
  13.  #  
  14.  #  Description: 
  15.  # 
  16.  # All procedures which deal with search/reg-search/grep type stuff
  17.  # in Alpha.
  18.  # ###################################################################
  19.  ##
  20.  
  21. namespace eval text {}
  22. namespace eval quote {}
  23. namespace eval file {}
  24.  
  25. proc quickFind {} {isearch}
  26. proc reverseQuickFind {} {rsearch}
  27. proc quickFindRegexp {} {regIsearch}
  28.  
  29. #================================================================================
  30. # 'greplist' and 'grepfset' are used for batch searching from the "find" dialog.
  31. #  Hence, you really shouldn't mess with them unless you know what you are doing.
  32. #================================================================================
  33. proc greplist {args} {
  34.     global tileLeft tileTop tileWidth tileHeight errorHeight
  35.     
  36.     set recurse [lindex $args 0]
  37.     set word [lindex $args 1]
  38.     set args [lrange $args 2 end]
  39.     
  40.     set num [expr {[llength $args] - 2}]
  41.     set exp [lindex $args $num]
  42.     set arglist [lindex $args [expr {$num + 1}]]
  43.     
  44.     set opened 0
  45.     set cid [scancontext create]
  46.     
  47.     set cmd [lrange $args 0 [expr {$num - 1}]]
  48.     eval scanmatch $cmd {$cid $exp {
  49.     if {!$word || [regexp -nocase -- "(^|\[^a-zA-Z0-9\])${exp}(\[^a-zA-Z0-9\]|\$)" $matchInfo(line)]} {
  50.         if {!$opened} {
  51.         set opened 1
  52.         win::SetProportions
  53.         set w [new -n {* Batch Find *} -m Brws -g $tileLeft $tileTop $tileWidth $errorHeight -tabsize 8]
  54.         insertText "(<cr> to go to match)\r-----\r"
  55.         }
  56.         set l [expr {20 - [string length [file tail $f]]}]
  57.         regsub -all "\t" $matchInfo(line) "  " text
  58.         insertText -w $w "\"[file tail $f]\"[format "%$l\s" ""]; Line $matchInfo(linenum): ${text}\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t∞$f\r"}
  59.     }
  60.     }
  61.     
  62.     foreach f $arglist {
  63.     message [file tail $f]
  64.     if {![catch {set fid [open $f]}]} {
  65.         scanfile $cid $fid
  66.         close $fid
  67.     }
  68.     }
  69.     scancontext delete $cid
  70.     
  71.     if {$opened} {
  72.     select [nextLineStart [nextLineStart [minPos]]] [nextLineStart [nextLineStart [nextLineStart [minPos]]]]
  73.     setWinInfo dirty 0
  74.     setWinInfo read-only 1
  75.     }
  76.     message ""
  77. }
  78.  
  79.  
  80. ## 
  81.  # -------------------------------------------------------------------------
  82.  # 
  83.  # "grepfset" --
  84.  # 
  85.  #  args: wordmatch ?-nocase? expression fileset
  86.  #  Obviously we ignore wordmatch
  87.  #  
  88.  #  If the 'Grep' box was set, then the search item is _not_ quoted.
  89.  #  
  90.  #  Non grep searching problems:
  91.  #  
  92.  #  If it wasn't set, then some backslash quoting takes place. 
  93.  #  (The chars: \.+*[]$^ are all quoted)
  94.  #  Unfortunately, this latter case is done incorrectly, so most
  95.  #  non-grep searches which contain a grep-sensitive character fail.
  96.  #  The quoting should use the equivalent of the procedure 'quote::Regfind'
  97.  #  but it doesn't quote () and perhaps other important characters.
  98.  #  
  99.  #  Even worse, if the string contained any '{' it never reaches this
  100.  #  procedure (there must be an internal error due to bad quoting).
  101.  # 
  102.  # -------------------------------------------------------------------------
  103.  ##
  104. proc grepfset {args} {
  105.     set num [expr {[llength $args] - 2}]
  106.     # the 'find' expression
  107.     set exp [lindex $args $num]
  108.     # the fileset
  109.     set fset [lindex $args [expr {$num + 1}]]
  110.     eval greplist 0 [lrange $args 0 [expr {$num-1}]] {$exp [getFileSet $fset]}
  111. }
  112.  
  113. proc grep {exp args} {
  114.     set files {}
  115.     foreach arg $args {
  116.     eval lappend files [glob -t TEXT -nocomplain -- $arg]
  117.     }
  118.     if {![llength $files]} {return "No files matched pattern"}
  119.     set cid [scancontext create]
  120.     scanmatch $cid $exp {
  121.     if {!$blah} {
  122.         set blah 1
  123.         set lines "(<cr> to go to match)\n"
  124.     }
  125.     set l [expr {20 - [string length [file tail $f]]}]
  126.     regsub -all "\t" $matchInfo(line) "  " text
  127.     append lines "\"[file tail $f]\"[format "%$l\s" ""]; Line $matchInfo(linenum): ${text}\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t∞$f\n"
  128.     }
  129.     
  130.     set blah 0
  131.     set lines ""
  132.     
  133.     foreach f $files {
  134.     if {![catch {set fid [open $f]}]} {
  135.         message [file tail $f]
  136.         scanfile $cid $fid
  137.         close $fid
  138.     }
  139.     }
  140.     scancontext delete $cid
  141.     return [string trimright $lines "\r"]
  142. }
  143.  
  144. proc grepnames {exp args} {
  145.     set files {}
  146.     foreach arg $args {
  147.     eval lappend files [glob -t TEXT -nocomplain -- $arg]
  148.     }
  149.     if {![llength $files]} {return "No files matched pattern"}
  150.     set cid [scancontext create]
  151.     scanmatch $cid $exp {
  152.     lappend filenames $f
  153.     }
  154.     set filenames ""
  155.     foreach f $files {
  156.     if {![catch {set fid [open $f]}]} {
  157.         message [file tail $f]
  158.         scanfile $cid $fid
  159.         close $fid
  160.     }
  161.     }
  162.     scancontext delete $cid
  163.     return $filenames
  164. }
  165.  
  166. ## 
  167.  # -------------------------------------------------------------------------
  168.  # 
  169.  # "performSearch" --
  170.  # 
  171.  #  Call this procedure in Tcl code which wants to use the standard procs
  172.  #  like 'replaceAll' to ensure flags like multi-file batch replace are
  173.  #  cleared.  Otherwise replaceAll might not have the desired effect.
  174.  #  
  175.  #  This proc is overridden by code (such as supersearch) which might
  176.  #  otherwise cause the nasty behaviour.
  177.  # -------------------------------------------------------------------------
  178.  ##
  179. proc performSearch {args} {
  180.     eval select [uplevel 1 search $args]
  181. }
  182.  
  183. proc findBatch {forward ignore regexp word pat} {
  184.     matchingLines $pat $forward $ignore $word $regexp 
  185. }
  186.  
  187. ## 
  188.  # -------------------------------------------------------------------------
  189.  #     
  190.  #    "containsSpace"    --
  191.  #    
  192.  #     Does the given    text contain any spaces?  In general we    don't complete
  193.  #     commands which    contain    spaces (although perhaps future    extensions
  194.  #     should    do this: e.g. cycle    through    'string    match',    'string    compare',…)
  195.  # -------------------------------------------------------------------------
  196.  ##
  197. proc containsSpace { cmd } { return [string match "*\[ \t\]*" $cmd] }
  198. proc containsReturn { cmd } { return [string match "*\[\r\n\]*" $cmd] }
  199.  
  200. ## 
  201.  # -------------------------------------------------------------------------
  202.  #     
  203.  #    "findPatJustBefore"    --
  204.  #    
  205.  #     Utility proc to check whether the first occurrence    of 'findpat'
  206.  #     to    the    left of    'pos' is actually an occurrence    of 'pat'. It can
  207.  #     be    used to    check if we're part    of an '} else {' (see TclelectricLeft)
  208.  #     or    in TeX mode    if we're in    the    argument of    a '\label{'    or '\ref{'
  209.  #     (see smartScripts)    for    example.
  210.  #     
  211.  #     A typical usage has the regexp    'pat' end in '$', so that it must
  212.  #     match all the text    up to 'pos'.  'matchw' can be used to store
  213.  #     the first '()'    pair match in the regexp.
  214.  #     
  215.  #     New: maxlook restricts how far this proc will search.  The default
  216.  #     is only 100 (not the entire file), after all this proc is supposed
  217.  #     to look 'just before'!
  218.  # -------------------------------------------------------------------------
  219.  ##
  220. proc findPatJustBefore { findpat pat {pos ""} {matchw ""} {maxlook 100} } {
  221.     if { $pos == "" } {set pos [getPos] }
  222.     if {[pos::compare $pos == [maxPos]]} { set pos [pos::math $pos - 1]}
  223.     if { $matchw != "" } { upvar $matchw word }
  224.     if {[llength [set res [search -s -n -f 0 -r 1 -l [pos::math $pos - $maxlook] -- "$findpat" $pos]]]} {
  225.     if {[regexp -- "$pat" [getText [lindex $res 0] $pos] dum word]} {
  226.         return [lindex $res 0]
  227.     }
  228.     }
  229.     return
  230. }
  231. # Look for pattern in filename after position afterPos and, if found, 
  232. # open the file quietly and select the pattern
  233. # author Jonathan Guyer
  234. proc selectPatternInFile {filename pattern {afterPos ""}} {
  235.     if {$afterPos == ""} {set afterPos [minPos]}
  236.     set searchResult [searchInFile $filename $pattern 1]
  237.     if {[pos::compare [lindex $searchResult 0] >= $afterPos]} {
  238.     placeBookmark
  239.     file::openQuietly $filename
  240.     eval select $searchResult
  241.     message "press <Ctl .> to return to original cursor position"
  242.     return 1
  243.     } else {
  244.     return 0
  245.     }
  246. }
  247.  
  248. proc text::replace {old new {fwd 1} {pos ""}} {
  249.     if {$pos == ""} {set pos [getPos]}
  250.     set m [search -s -f $fwd -m 0 -r 0 -- $old $pos]
  251.     eval replaceText $m [list $new]
  252. }
  253.  
  254. proc isSelection {} {
  255.     return [pos::compare [getPos] != [selEnd]]
  256. }
  257. proc searchStart {} {
  258.     global search_start
  259.     select [getPos]
  260.     setMark
  261.     if {[catch {goto $search_start}]} {message "No previous search"}
  262. }
  263. set {patternLibrary(Pascal to C Comments)}      { {\{([^\}]*)\}}    {/* \1 */} }
  264. set {patternLibrary(C++ to C Comments)}        { {//(.*)}    {/* \1 */} }
  265. set {patternLibrary(Space Runs to Tabs)}    { { +}    {\t}}
  266.  
  267. proc getPatternLibrary {} {
  268.     global patternLibrary
  269.     
  270.     foreach nm [array names patternLibrary] {
  271.     lappend nms [concat [list $nm] $patternLibrary($nm)]
  272.     }
  273.     return $nms
  274. }
  275.  
  276. # This fails if, say, search string is '\{[^}]'
  277. # This is because the '}' ends the first argument because this
  278. # procedure is presumably called internally with incorrect quoting.
  279. proc rememberPatternHook {search replace} {
  280.     global patternLibrary modifiedArrayElements
  281.     if {[catch {set name [prompt "New pattern's name?" ""]}]} {
  282.     return ""
  283.     }
  284.     lappend modifiedArrayElements [list $name patternLibrary]
  285.     set patternLibrary($name) [list $search $replace]
  286.     return $name
  287. }
  288.  
  289. proc deletePatternHook {} {
  290.     global patternLibrary modifiedArrayElements
  291.     set temp [list prompt "Delete which pattern?" [lindex [array names patternLibrary] 0] "Pats:"]
  292.     set name [eval [concat $temp [array names patternLibrary]]]
  293.     lappend modifiedArrayElements [list $name patternLibrary]
  294.     unset patternLibrary($name)
  295. }
  296.  
  297. ## 
  298.  # -------------------------------------------------------------------------
  299.  # 
  300.  # "regIsearch" -- REGular expression Iterative SEARCH
  301.  # 
  302.  # This version allows class shorthands (\d \s \w \D \S \W), 
  303.  # word anchors (\b), and some aliases of the machine dependent 
  304.  # control characters (\a \f \e \n \r \t). Therefore, 
  305.  # we need two prompts, one for when we have a valid pattern, and one 
  306.  # for when the pattern has gone invalid (most likely due to starting 
  307.  # to enter one of the above patterns). 
  308.  # 
  309.  # The Return key aborts it  and the point goes back to the 
  310.  # original $pos. You can then use 'exchangePointAndMark' 
  311.  # (cntrl-x, cntrl-x -in emacs keyset) to jump back and forth 
  312.  # between where the search started from, to where the search was
  313.  # ended.
  314.  # 
  315.  # The Escape key or Mouse-click "exits" it, (as does "abortEm" -bound 
  316.  # to cntrl-g), as well as most modifier-key-combinations
  317.  # (except for Shift, and any combination whose  binding's 
  318.  # functionality makes sense -see regComp below). Also the 
  319.  # up & down Arrow keys, exit it. An exit differs from an abort in that, 
  320.  # in the former, the selection is left at the last search result.
  321.  # 
  322.  # 
  323.  # The next occurrence of the current pattern can be matched by typing 
  324.  # either control-s (to get the next occurence forward), or control-r 
  325.  # (to get the the next occurrence backward)
  326.  #
  327.  # Also, after aborting, the search string is left in the Find dialog,
  328.  # and so you can use 'findAgain', but, be aware that the Find dialog
  329.  # starts out with a default of <Grep=OFF>.
  330.  #  
  331.  # Original Author: Mark Nagata
  332.  # modifications  : Tom Fetherston
  333.  # -------------------------------------------------------------------------
  334.  ##
  335. proc regIsearch {} {
  336.     
  337.     set ignoreCase 0
  338.     set patt ""
  339.     set pos [getPos]
  340.     
  341.     set done 0
  342.     while {!$done} {
  343.     # check pattern validatity
  344.     if {[catch {regexp -- $patt {} dmy} dmy]} {        
  345.         set prompt "building->: $patt"
  346.     } else {
  347.         set prompt "regIsearch: $patt"
  348.     } 
  349.     switch -- [catch {status::prompt $prompt regComp "anything"} res] {
  350.         0 {
  351.         # got a keystroke that triggered a normal end (e.g. <return>)
  352.         goto $pos
  353.         message "Aborted: $patt"
  354.         return
  355.         }
  356.         1 {
  357.         # an error was generated
  358.         if {[string match "missing close-brace" $res]} {
  359.             # must have typed a slash, so:
  360.             append patt "\\"
  361.             continue
  362.         } else {
  363.             # alertnote $res
  364.             set done 1
  365.         }
  366.         
  367.         }
  368.         default {
  369.         set done 1
  370.         }
  371.     }
  372.     }
  373.     
  374.     message " Exited: $patt"
  375. }
  376.  
  377.  
  378. ## 
  379.  # -------------------------------------------------------------------------
  380.  # 
  381.  # "regComp" -- REGisearch COMmand line input character Processor
  382.  # 
  383.  #  This proc handles each keypress while running a regIsearch. It has been 
  384.  #  modified from Mark Nagata's original to provide next ocurrence 
  385.  #  before/after current, and support for key bindings whose navigation or 
  386.  #  text manipulation functionality makes sense with respect to a regIsearch.
  387.  #  
  388.  #  closest occurence before current match    
  389.  #    - command-option g & cntrl-r (mnemonic 'reverse')
  390.  #  closest occurence after current match
  391.  #    - command g & cntrl-s (mnemonic 'successor')
  392.  #  
  393.  #                         Text Naviagation
  394.  #  forwardChar (aborts and leaves cursor after last match)
  395.  #    - right arrow & cntrl-f (emacs)
  396.  #  backwardChar (aborts and leaves cursor before last match)
  397.  #    - left arrow & cntrl-b (emacs)
  398.  #  beginningOfLine (aborts and moves cursors to the start of the line 
  399.  #      containing the last match)
  400.  #    - cmd left arrow & cntrl-a (emacs)
  401.  #  beginningOfLine (aborts and moves cursors to the start of the line 
  402.  #      containing the last match)
  403.  #    - cmd right arrow & cntrl-e (emacs)
  404.  #  
  405.  #                         Text Manipulation
  406.  #  deleteSelection (aborts and deletes selection)
  407.  #    - cntrl-d (emacs)
  408.  #  killLine (aborts and deletes from start of selection to end of line)
  409.  #    - cntrl-k (emacs)
  410.  #  
  411.  # -------------------------------------------------------------------------
  412.  ##
  413. proc regComp {curr {key 0} {mod 0}} {
  414.     set direction {}
  415.     
  416.     # build a string that represents all the modifiers pressed:
  417.     # checking in this order cmd, shift, option, and ctrl
  418.     if {[expr {$mod & 1}]} { append t "c" } else { append t "_" }
  419.     if {[expr {$mod & 34}]} { append t "s" } else { append t "_" }
  420.     if {[expr {$mod & 72}]} { append t "o" } else { append t "_" }
  421.     if {[expr {$mod & 144}]} { append t "z" } else { append t "_" }
  422.     
  423.     scan $key %c decVal
  424.     
  425.     switch -- $t {
  426.     "____" {
  427.         switch -- $decVal {
  428.         29 {forwardChar ;         break; # right arrow; }
  429.         28 {backwardChar ;         break; # left arrow; }
  430.         30 {                        break; # up arrow; }
  431.         31 {                        break; # down arrow; }
  432.         }
  433.     }
  434.     }
  435.     
  436.     switch -- $t {
  437.     "____" - 
  438.     "_s__" {
  439.         upvar patt pat
  440.         if {$curr != ""} {
  441.         while {[string compare [string range $pat [string last $curr $pat] end] $curr] != 0} {
  442.             set newEnd [expr {[string length $pat] - 2}]
  443.             if {$newEnd < 0} {
  444.             error "deleted past string start"
  445.             } 
  446.             set pat [string range $pat 0 $newEnd] 
  447.         }
  448.         } 
  449.         
  450.         set preAppend $pat
  451.         append pat $key
  452.         if {[catch {regexp -- $pat {} dmy} res]} {
  453.         message "building->: $preAppend"
  454.         } else {
  455.         message "regIsearch: $preAppend" 
  456.         upvar ignoreCase ign
  457.         set searchResult [search -n -f 1 -m 0 -i $ign -r 1 -- $pat [getPos]]
  458.         if {[llength $searchResult] == 0} {
  459.             beep
  460.         } else {
  461.             select [lindex $searchResult 0] [lindex $searchResult 1]
  462.         }
  463.         } 
  464.         return $key
  465.         
  466.     }
  467.     "c___" {
  468.         switch -- $decVal {
  469.         103 { set direction fwd;        # (cmd g); }
  470.         28 {beginningOfLine ;     break; # cmd left arrow; }
  471.         29 {endOfLine ;         break; # cmd right arrow; }
  472.         }
  473.         
  474.     }
  475.     "___z" {
  476.         # If the user is using the emacs key bindings, check for ones that 
  477.         # make sense. All other control key combinations abort
  478.         if {[package::active emacs]} {
  479.         switch -- $decVal {
  480.             6 {forwardChar ;         break; # cntrl-f; }
  481.             2 {backwardChar ;     break; # cntrl-b; }
  482.             1 {beginningOfLine ;     break; # cntrl-a; }
  483.             5 {endOfLine ;         break; # cntrl-e; }
  484.             4 {deleteSelection ;     break; # cntrl-d; }
  485.             10 {killLine ;         break; # cntrl-k; }
  486.         }
  487.         } 
  488.         # See if user has requested to find another match, either searchForward 
  489.         # (cntrl-s) or reverseSearch (cntrl-r). Set flag accordingly
  490.         switch -- $decVal {
  491.         115 - 19 { set direction fwd; # (cntrl-s); }
  492.         114 - 18 { set direction bckwd; # (cntrl-r); }
  493.         default {return {} }
  494.         }
  495.     }
  496.     "c_o_" {
  497.         switch -- $decVal {
  498.         169 { set direction bckwd; # (cmd-opt 'g'); }
  499.         default {return {} }
  500.         }
  501.         
  502.     }
  503.     "default" {
  504.         beep
  505.         error "modifier combination has no meaningful bindings with respect to regIsearch"
  506.     }
  507.     }
  508.     # handle direction flag if it got set above
  509.     if {$direction != ""} {
  510.     upvar patt pat
  511.     upvar ignoreCase ign
  512.     if {[string match $direction fwd]} {
  513.         set dir 1
  514.         set search_start [pos::math [getPos] + 1]
  515.     } else {
  516.         set dir 0
  517.         set search_start [pos::math [getPos] - 1]
  518.     } 
  519.     set searchResult [search -n -f $dir -m 0 -i $ign -r 1 -- $pat $search_start]
  520.     if {[llength $searchResult] == 0} {
  521.         beep
  522.     } else {
  523.         select [lindex $searchResult 0] [lindex $searchResult 1]
  524.     }
  525.     return {}
  526.     } 
  527. }
  528.  
  529.  
  530. proc choicesProc {curr c} {
  531.     global choiceList
  532.     if {$c != "\t"} {return $c}
  533.     
  534.     set matches {}
  535.     foreach w $choiceList {
  536.     if {[string match "$curr*" $w]} {
  537.         lappend matches $w
  538.     }
  539.     }
  540.     if {![llength $matches]} {
  541.     beep
  542.     } else {
  543.     return [string range [largestPrefix $matches] [string length $curr] end]
  544.     }
  545.     return ""
  546. }
  547.  
  548.  
  549. proc sPromptChoices {msg def choiceListIn} {
  550.     global useStatusBar choiceList
  551.     set choiceList $choiceListIn
  552.     if {[catch {statusPrompt -f "$msg ($def): " choicesProc} ans]} {
  553.     error "cancel"
  554.     }
  555.     if {![string length $ans]} {return $def}
  556.     return $ans
  557. }
  558.  
  559. proc nextFunc {} {
  560.     searchFunc 1
  561. }
  562.  
  563. proc prevFunc {} {
  564.     searchFunc 0
  565. }
  566.  
  567. proc jumpNextFunc {} {
  568.     searchFunc 3
  569. }
  570.  
  571. proc jumpPrevFunc {} {
  572.     searchFunc 2
  573. }
  574.  
  575. proc searchFunc {code} {
  576.     set pos [getPos]
  577.     
  578.     #to allow us to handle special cases
  579.     set funcExpr [get_funcExpr $code]
  580.     
  581.     select $pos
  582.     
  583.     switch -- $code {
  584.     "1" -
  585.     "3" {
  586.         set pos [pos::math $pos + 1]
  587.         set lastStop [maxPos]
  588.         set dir 1
  589.     }
  590.     "0" -
  591.     "2" {
  592.         set pos [pos::math $pos - 1]
  593.         set lastStop [minPos]
  594.         set dir 0
  595.     }
  596.     }
  597.     
  598.     if {![catch {search -s -f $dir -i 1 -r 1 -- $funcExpr $pos} res]} {
  599.     eval select $res
  600.     } elseif {$code == 3} {
  601.     searchFunc 1
  602.     } else {
  603.     goto $lastStop
  604.     if {$dir} {
  605.         message "At bottom, no more functions in this direction"
  606.     } else {
  607.         message "At top, no more functions in this direction"
  608.     }
  609.     }
  610. }
  611.  
  612. proc get_funcExpr {dir} {
  613.     global funcExpr mode
  614.     switch -- $mode {
  615.     "Tcl" {
  616.         if {[regexp "^\\* Trace" [win::CurrentTail]]} {
  617.         switch $dir {
  618.             "0" -
  619.             "1" {
  620.             set searchExpr {(^ *[\w:]+ $)|(^ *[^ ']+ ')}
  621.             }
  622.             "2" {
  623.             if {[regexp {(^.*)OK:} [getSelect] blah searchExpr]} {
  624.                 set searchExpr "^${searchExpr}"
  625.             } else {
  626.                 set searchExpr {(^ *[\w:]+ $)|(^ *[^ ']+ ')}
  627.             }
  628.             }
  629.             "3" {
  630.             regexp {(^[^']*)'?} [getSelect] blah searchExpr
  631.             set searchExpr "^${searchExpr}OK:"
  632.             }
  633.         }
  634.         } else {
  635.         set searchExpr $funcExpr 
  636.         } 
  637.     }
  638.     default {
  639.         set searchExpr $funcExpr 
  640.     }
  641.     }
  642.     return $searchExpr     
  643. }
  644.  
  645. proc sPrompt {msg def} {
  646.     global useStatusBar
  647.     if {!$useStatusBar} {return [prompt $msg $def]}
  648.     if {[catch {statusPrompt "$msg ($def): "} ans]} {
  649.     error "cancel"
  650.     }
  651.     if {![string length $ans]} {return $def}
  652.     return $ans
  653. }
  654.  
  655. ###
  656. #===========================================================================
  657. # Juan Falgueras (7/Abril/93)
  658. # you only need to select (or not) text and move *forward and backward*
  659. # faster than iSearch (if you have there the |word wo|rd..).
  660. #===========================================================================
  661.  
  662. proc quickSearch {dir} {
  663.     if {[pos::compare [selEnd] == [getPos]]} {
  664.     backwardChar
  665.     hiliteWord
  666.     }
  667.     set myPos [expr {$dir ? [selEnd] : [pos::math [getPos] - 1]}]
  668.     set text [getSelect]
  669.     set searchResult [search -s -n -f $dir -m 0 -i 1 -r 0 $text $myPos]
  670.     if {[llength $searchResult] == 0} {
  671.     beep
  672.     message [concat [expr {$dir ? "->" : "<-"}] '$text' " not found"]
  673.     return 0
  674.     } else {
  675.     message [concat [expr {$dir ? "->" : "<-"}] '$text']
  676.     eval select $searchResult
  677.     return 1
  678.     }
  679. }
  680.  
  681.